package cn.mulanbay.gateway.filter;

import com.alibaba.fastjson.JSON;
import cn.mulanbay.business.bean.LoginUser;
import cn.mulanbay.business.handler.TokenHandler;
import cn.mulanbay.common.bean.ResultBean;
import cn.mulanbay.common.config.CacheKey;
import cn.mulanbay.common.config.Constants;
import cn.mulanbay.common.exception.ErrorCode;
import cn.mulanbay.common.util.StringUtil;
import cn.mulanbay.gateway.config.IgnoreWhiteProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 网关鉴权
 *
 * @author fenghong
 * @create 2022-01-16 10:00
 */
@RefreshScope
@Component
public class AuthFilter implements GlobalFilter, Ordered {

    private static final Logger logger = LoggerFactory.getLogger(AuthFilter.class);

    @Autowired
    private IgnoreWhiteProperties ignoreWhite;

    @Autowired
    TokenHandler tokenHandler;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String url = exchange.getRequest().getURI().getPath();
        logger.debug("网关收到请求：" + url);

        // 跳过不需要验证的路径
        if (StringUtil.matches(url, ignoreWhite.getWhites())) {
            return chain.filter(exchange);
        }
        LoginUser user = tokenHandler.getLoginUser(this.getTokenFromHeader(exchange.getRequest()));
        if (user == null) {
            ResultBean rb = new ResultBean();
            rb.setCode(ErrorCode.USER_NOT_LOGIN);
            rb.setMessage("用户未登录");
            return this.setUnauthorizedResponse(exchange,rb);
        }
        //刷新token
        tokenHandler.verifyToken(user);
        Long userId = user.getUserId();
        Long roleId = user.getRoleId();
        // 设置用户信息到请求并清除内部认证
        ServerHttpRequest mutableReq = exchange.getRequest().mutate()
                .header(CacheKey.DETAILS_USER_ID, userId.toString())
                .header(CacheKey.DETAILS_ROLE_ID, roleId==null ? "":roleId.toString())
                .headers(httpHeaders -> httpHeaders.remove(Constants.FEIGN_AUTH_HEADER))
                .build();
        ServerWebExchange mutableExchange = exchange.mutate().request(mutableReq).build();

        return chain.filter(mutableExchange);
    }

    /**
     * 未授权
     * @param exchange
     * @param rb
     * @return
     */
    private Mono<Void> setUnauthorizedResponse(ServerWebExchange exchange, ResultBean rb) {
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        response.setStatusCode(HttpStatus.OK);
        logger.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
        return response.writeWith(Mono.fromSupplier(() -> {
            DataBufferFactory bufferFactory = response.bufferFactory();
            return bufferFactory.wrap(JSON.toJSONBytes(rb));
        }));
    }

    /**
     * 从header里面获取
     *
     * @param request
     * @return
     */
    private String getTokenFromHeader(ServerHttpRequest request) {
        String token = request.getHeaders().getFirst(CacheKey.HEADER);
        if (StringUtil.isNotEmpty(token) && token.startsWith(CacheKey.TOKEN_PREFIX)) {
            token = token.replace(CacheKey.TOKEN_PREFIX, "");
        }
        return token;
    }

    @Override
    public int getOrder() {
        return -200;
    }
}
